/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ResultEditor.AnnotationClasses;

import java.awt.Color;
import java.io.File;
import java.util.Arrays;
import java.util.Vector;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

/**
 *
 * @author leng
 */
public class ShowClassesInTreeView {

    // the treeview component in the GUI of result editor
    protected JTree treeview;
    // handle of main GUI for function recall
    protected static UserInterface.GUI gui;

    /**
     * Constructor
     *
     * @param   treeview
     *          Introduce the component from GUI of result editor.
     *
     * @param   gui
     *          Introduce the handle of main GUI for function recall.
     */
    public ShowClassesInTreeView( JTree treeview, UserInterface.GUI gui  ){
        this.treeview = treeview;
        ShowClassesInTreeView.gui = gui;
    }

    private static String currentArticle = null;

    public ShowClassesInTreeView(){
    }

    /**show classnames in tree view*/
    public void display(){
        
        String currentFilename = null;
        try{
            // ##1## clear contents and reset root node in the tree view
            clearDisplay();
            setRootNodeContent();
            
            File f = ResultEditor.WorkSpace.WorkSet.getCurrentFile();
            if(f==null){
                System.out.println("####ERROR 1106091547:: can not get current document - CURRENTFILE==NULL !!!");
                return;
            }
            
            currentFilename = f.getName();

            if (( currentFilename == null )||(currentFilename.trim().length()<1)){
                System.out.println("####ERROR 1103211007:: can not find current raw file name!!!");
                return;
            }
            if ( treeview == null ){
                System.out.println("####ERROR 1103211006:: lost point for accessing the component of treeview!!!");
                return;
            }

            
            //refreshTypeMemory();

            // get all classnames in array of string
            String[] classnames = classnames( classnames() );
            // get root of treeview
            DefaultMutableTreeNode  root = (DefaultMutableTreeNode ) treeview.getModel().getRoot();
            if(root==null) {
                System.out.println("####ERROR 1103211002:: fail to get access to the root!!!");
                return;
            }

            // ##2## assemble nodes of markables/classes
            // reach depot of all classes(markables)
            ResultEditor.AnnotationClasses.Depot depot = new  ResultEditor.AnnotationClasses.Depot();
            
            for( int i=0; i<classnames.length; i++ )
            {

                treeview.setRootVisible(true);
                String classname = classnames[i];

                if ((classname == null) ||(classname.trim().length()<1))
                    continue;

                ResultEditor.AnnotationClasses.AnnotatedClass annotatedclass
                        = depot.getAnnotatedClass( classname );
                if(annotatedclass==null)
                    return;
                
                boolean isSelected =  SelectedStatus.getSelectedStatus( classname );

                int annotationAmount_toThisClass = annotatedclass.getAnnotationAmount();
                int annotationTypeAmount_toThisClass = annotatedclass.getAnnotationTypeAmount();

                // ##2.1## add node of class to the root of the treeview
                Treeview_ClassNode classnode = new Treeview_ClassNode( classname.trim(), isSelected,
                        annotatedclass.backgroundColor, annotationAmount_toThisClass,
                        annotationTypeAmount_toThisClass);

                if ( env.Parameters.currentMarkables_to_createAnnotation_by1Click != null )
                    if ( classname.trim().equals( env.Parameters.currentMarkables_to_createAnnotation_by1Click ) )
                        classnode.setFlag_isSelected_toCreateAnnotation(true);


                // ##2.1.1## get color of this class/markable
                Color classcolor = this.getColorByClass(classname.trim());


                // ##3## assemble nodes of annotation types
                if ( annotatedclass != null )
                {
                    for( ResultEditor.AnnotationClasses.AnnotationType at 
                            : annotatedclass.getAnnotationTypes() )
                    {
                        Treeview_AnnotationNode annotationnode = new Treeview_AnnotationNode( at.name.trim(), at.amount );

                        boolean isAppeared_in_CurrentArticle = false;
                        if ( at.subAnnotations != null ){
                            //System.out.println( "1 - " + at.subAnnotations.size() );
                            for( file_annotation fa : at.subAnnotations ) {
                                if ( fa == null )
                                    continue;

                                annotationnode.addAnnotations( fa );
                                //System.out.println( " - " );

                                if (( fa.filename == null )||(currentFilename==null))
                                    continue;
                                if ( currentFilename.equals( fa.filename.trim() ) )
                                    isAppeared_in_CurrentArticle = true;
                            }
                        }else{
                            System.out.println("1008190215 - data lost!!!");
                        }

                        annotationnode.isNotAppeared_in_CurrentArticle = ! isAppeared_in_CurrentArticle;
                        annotationnode.setClassColor( classcolor );


                        classnode.add( annotationnode );
                    }
                }
                // add annotation type to this newly built class node
                root.add( classnode );

                SelectedStatus.add( classnames[i].trim(), isSelected );

            }



            // set renderer and cell editor for custom component
            Treeview_NodeRenderer renderer = new Treeview_NodeRenderer();

            treeview.setCellRenderer(renderer);
            treeview.setCellEditor(new Treeview_ClassNodeEditor(treeview));
            //treeview.addTreeSelectionListener(new SelectionListener());
            treeview.setEditable(true);
        


            // set node status : selected and expansion status
            setNodesStatus();

            // update
            treeview.updateUI();
        }catch(Exception e){
            System.out.println("ERROR 1104212200::"+e.toString());
        }
    }

    @SuppressWarnings("static-access")
    private Color getColorByClass(String classname){
        if ( classname == null )
            return Color.black;

        ResultEditor.AnnotationClasses.Depot classdepot = new ResultEditor.AnnotationClasses.Depot();
        Color color = classdepot.getColor(classname);
        if ( color == null )
            return Color.black;
        else
            return color;
    }

    /**
     * To all node in the treeview, set their selected status and expansion
     * status as previous tree view.
     */
    public void setNodesStatus(){
        // ##1##  try to get root node
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeview.getModel().getRoot();
        if ( root == null )
            return;

        // ##2## try to get each class/markable node from the root node
        int markables_amount = root.getChildCount();
        for( int i = 0 ; i < markables_amount; i++ ){
            Treeview_ClassNode classnode = ( Treeview_ClassNode ) root.getChildAt(i);
            if( classnode.getText() != null ){
                String classname = classnode.getText().trim();
                if ( isClassNodeExpanded( classname ) ){
                      TreePath path = new TreePath(getTreeModel().getPathToRoot(classnode));
                      if ( path != null )
                          treeview.expandPath(path);
                }
            }
        }
        
    }

    /**
     * To a tree node of class/markables, its expension status may be expanded
     * or not in the latest view. This method help us to find the latest
     * expension status of your designated class/markable.
     *
     * @return  true - If node was expanded;
     *          false - if node was not expaned.
     */
    public boolean isClassNodeExpanded(String classname){

        // validity check
        if ( classname == null )
            return false;
        if ( classname.trim().length() < 1 )
            return false;

        // try to get the class/markable
        ResultEditor.AnnotationClasses.Depot depot = new ResultEditor.AnnotationClasses.Depot();
        ResultEditor.AnnotationClasses.AnnotatedClass markable = depot.getAnnotatedClass(classname);
        if ( markable == null )
            return false;

        // get saved expansion status
        return markable.isNodeExpanded;

    }

    public void refreshTypeMemory_currentArticle(String currentArticle){
        if ((currentArticle != null)&&(currentArticle.trim().length() < 1))
            currentArticle = null;
        ShowClassesInTreeView.currentArticle = currentArticle;

        refreshTypeMemory_refresh();
    }

    public void refreshTypeMemory_all(){
        ShowClassesInTreeView.currentArticle = null;
        refreshTypeMemory_refresh();
    }

    public void refreshTypeMemory_refresh(){
        ResultEditor.AnnotationClasses.Depot depot = new ResultEditor.AnnotationClasses.Depot();
        depot.checkAllAnnotationTypes( ShowClassesInTreeView.currentArticle );
    }

    private Color getColor(String classname){
        if( classname == null ) return null;
        classname = classname.trim();
        return ResultEditor.AnnotationClasses.Depot.getColor( classname );
    }


    /**Remove all treeview nodes of this treeview except root node.*/
    private void clearDisplay(){
        try{
            DefaultMutableTreeNode  root = (DefaultMutableTreeNode ) treeview.getModel().getRoot();
            if ( root == null )  return;
            root.removeAllChildren();
        }catch(Exception ex){
            System.out.println("####ERROR 1103211005:: fail to remove all items from the treeview!!!");
        }
    }

    /**set text of root node of the tree view. Show class and amount of classes
     * and related subAnnotations.*/
    private void setRootNodeContent(){
        try{
            DefaultMutableTreeNode  root = (DefaultMutableTreeNode ) treeview.getModel().getRoot();
            if ( root == null )  return;

            Vector<String> roots = new Vector<String>();

            String categories = "<html> <font color=green>"
                    + ResultEditor.AnnotationClasses.Depot.size()
                    + "</font> Markables: <font color=gray>["
                    + Depot.TYPE_getAnnotationTypeAmount()
                    + "/"
                    + getAnnotationsAmount()
                    + " annotations]<font><html>";
            roots.add( categories );
            root.setUserObject( categories );
        }catch(Exception ex){
            System.out.println("####ERROR 1103211004:: fail to put roots on the treeview!!!");
        }
    }

    /**get amount of all subAnnotations in memory(depot of subAnnotations)*/
    private int getAnnotationsAmount(){
        ResultEditor.Annotations.Depot depot = new ResultEditor.Annotations.Depot();
        if ( depot == null )   return 0;

        // count annotation amount of each article
        int amount = 0;
        for( ResultEditor.Annotations.Article article: depot.getAllArticles() ){
            if ( article.annotations == null )  continue;
            if (( ShowClassesInTreeView.currentArticle != null )&&( ShowClassesInTreeView.currentArticle.trim().length() > 0  ))
                if(( article.filename != null )&&(article.filename.trim().length() > 0)){
                    if( article.filename.trim().compareTo(currentArticle.trim())!= 0 )
                        continue;
                }else continue;


            amount = amount + article.annotations.size();
        }

        return amount;
    }

    /**get all classnames in array of objects*/
    private String[] classnames(){
        Depot depot = new Depot();
        return depot.getAnnotationClasssnamesString();
    }

    /**get strings of classnames by converting object to string.*/
    private String[] classnames(Object[] objects){
        if ( objects == null )
            return null;

        int size = objects.length;
        String[] returnClassnames = new String[size];

        Arrays.sort(objects);

        for( int i=0; i<size; i++ ){
            returnClassnames[i] = (String) objects[i];
        }

        return returnClassnames;
    }

    /**every time while user change the selected staus of a class node, this method
     * bring change to the manager of class selected status: class SelectedStatus.
     * And then only show annotation belongs to classes which selected by user.
     */
    public void checkStatusChanged(String classname, boolean isSelected){
        SelectedStatus.changeSelectedStatus(classname, isSelected);

        setAnnotationsVisile();

        repaintBackgroundHighlight();
        gui.showValidPositionIndicators();
    }

    private void repaintBackgroundHighlight(){
        gui.repaintHighlighter();
    }

    /**Set visiable attributes of all subAnnotations in the memory. To each annotaiton,
     * its attribute 'visible' will be set to false if its annotated class appeared
     * in the list of unchosen classes in class 'SelectedStatus'.*/
    public void setAnnotationsVisile(){
        ResultEditor.Annotations.Depot depot = new ResultEditor.Annotations.Depot();
        depot.setAnnotationVisible( SelectedStatus.getVisibleClasses() );
    }

    private DefaultTreeModel getTreeModel(){
        return (DefaultTreeModel)treeview.getModel();
    }

    /**clear for any highlighted specific category node in the treevide's background showed as focused.*/
    public void removeAllNodehighlight(){

        try{
            if(treeview == null)    return;

            // get root
            DefaultMutableTreeNode rootnode = (DefaultMutableTreeNode) treeview.getModel().getRoot();
            if ( rootnode == null )
                return;

            // go over all category node
            int categoryNodeAmount = rootnode.getChildCount();
            for(int i=0; i< categoryNodeAmount; i++ ){
                DefaultMutableTreeNode thisnode = (DefaultMutableTreeNode) rootnode.getChildAt(i);
                if ( thisnode == null ) continue;
                if ( thisnode instanceof Treeview_ClassNode ){

                    try{
                        int size = thisnode.getChildCount();
                        for( int j=0; j< size; j++ ){
                            Object o = thisnode.getChildAt(j);
                            if(( o != null  )&&(o instanceof Treeview_AnnotationNode )){

                                DefaultMutableTreeNode temp = (DefaultMutableTreeNode)thisnode.getChildAt(j);
                                Treeview_AnnotationNode an = (Treeview_AnnotationNode)o;
                                an.isHighLighted = false;
                                ((DefaultMutableTreeNode)o).setUserObject( an );

                            }

                        }

                    }catch(Exception ex){

                    }
                }

            }
        }catch(Exception ex){
            System.out.println("errors 1010281344:: fail to clear all nodes");
        }

    }


    /**let a specific category node in the treevide's background showed as focused.*/
    public void setCategoryNodeSelected(String category, String annotation_type_text){

        // Do NOTHING if user's mouse clicked on navigator panel, so that
        // the selection indicator can works normal.
        if( ResultEditor.WorkSpace.WorkSet.mouse_clicked_on == 1)
            return;

        // force change and display the selection items
        if( category == null )  return;
        if( category.trim().length() < 1 )  return;
        if(treeview == null)    return;

        DefaultMutableTreeNode rootnode = (DefaultMutableTreeNode) treeview.getModel().getRoot();
        if ( rootnode == null )
            return;

        int categoryNodeAmount = rootnode.getChildCount();
        for(int i=0; i< categoryNodeAmount; i++ ){
            DefaultMutableTreeNode thisnode = (DefaultMutableTreeNode) rootnode.getChildAt(i);
            if ( thisnode == null ) continue;
            if ( thisnode instanceof Treeview_ClassNode ){
                String categoryname = ((Treeview_ClassNode)thisnode).text;
                if ( categoryname == null ) continue;
                if ( categoryname.trim().length() < 1 ) continue;
                if( categoryname.trim().compareTo(category.trim()) ==0 ) {
                    TreePath visiblePath = new TreePath(getTreeModel().getPathToRoot(thisnode));
                    treeview.setSelectionPath( visiblePath );
                    
                    // set selection indicator for annotation
                    if( annotation_type_text != null ){
                        int size = thisnode.getChildCount();
                        for( int j=0; j< size; j++ ){
                            Object o = thisnode.getChildAt(j);
                            if(( o != null  )&&(o instanceof Treeview_AnnotationNode )){
                                
                                DefaultMutableTreeNode temp = (DefaultMutableTreeNode)thisnode.getChildAt(j);
                                Treeview_AnnotationNode an = (Treeview_AnnotationNode)o;
                                String text = an.uniqueAnnotationText;
                                if( an.uniqueAnnotationText.equals( annotation_type_text ) ){
                                    an.isHighLighted = true;
                                }else{
                                    an.isHighLighted = false;
                                }

                                ((DefaultMutableTreeNode)thisnode).setUserObject( an );
                                
                            }

                        }
                    }
                    
                }else{
                    int size = thisnode.getChildCount();
                        for( int j=0; j< size; j++ ){
                            Object o = thisnode.getChildAt(j);
                            if(( o != null  )&&(o instanceof Treeview_AnnotationNode )){

                                DefaultMutableTreeNode temp = (DefaultMutableTreeNode)thisnode.getChildAt(j);
                                Treeview_AnnotationNode an = (Treeview_AnnotationNode)o;
                                String text = an.uniqueAnnotationText;

                                    an.isHighLighted = false;


                                ((DefaultMutableTreeNode)thisnode).setUserObject( an );

                            }

                        }
                }

            }
        }
        // System.out.println( "current path in treeview = " + visiblePath );
        treeview.updateUI();
        return;
    }
}

class SelectedStatus{
    private static Vector<ItemSelectedStatus> depot = new Vector<ItemSelectedStatus>();

    public static void add(String classname, boolean isSelected){
        if( isExisted( classname ) ) return;
        ItemSelectedStatus iss = new ItemSelectedStatus( classname, isSelected );
        depot.add(iss);
    }

    public static void changeSelectedStatus(String classname, boolean isSelected){
        if( !isExisted( classname ) ) {
            add( classname, isSelected );
        }else {
            for(ItemSelectedStatus iss: depot){
            if ( iss == null )
                continue;
            if( iss.classname.trim().compareTo(classname.trim()) == 0 )
                iss.isSelected = isSelected;
        }
        }
    }

    /**return these classnames which are not selected by user.*/
    public static Vector<String> getVisibleClasses(){
        Vector<String> toReturn = new Vector<String>();
        if ( depot != null ){
            for( ItemSelectedStatus iss: depot ){
                if ( ( iss == null ) || ( iss.classname == null ) )
                    continue;
                if ( !iss.isSelected )
                    toReturn.add( iss.classname.trim() );

            }
        }
        return toReturn;

    }

    public static boolean getSelectedStatus(String classname){
        for(ItemSelectedStatus iss: depot){
            if ( iss == null )
                continue;
            if( iss.classname.trim().compareTo(classname.trim()) == 0 )
                return iss.isSelected;
        }
        return true;
    }

    private static boolean isExisted(String classname){
        for(ItemSelectedStatus iss: depot){
            if ( iss == null )
                continue;
            if( iss.classname.trim().compareTo(classname.trim()) == 0 )
                return true;
        }
        return false;
    }
}

class ItemSelectedStatus{
    String classname;
    boolean isSelected = true;

    public ItemSelectedStatus(){
    }

    public ItemSelectedStatus( String classname, boolean isSelected ){
        this.classname = classname;
        this.isSelected = isSelected;
    }
}